﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.IO;
using System.Configuration;
using System.Net;

namespace CommModule.Connection
{
    internal class TCPSocket
    {
        private readonly int _socketTimeout = 120000;
        private readonly int _bufferSize = 1024;

        private Socket _tcpSocket;

        public TCPSocket()
        {
            IPAddress ipAddress = IPAddress.Parse(ConfigurationManager.AppSettings["CERTCOPAddress"].ToString());
            int localEndpointPort = Int32.Parse(ConfigurationManager.AppSettings["MyPort"].ToString());
            IPEndPoint localEndpoint = new IPEndPoint(ipAddress, localEndpointPort);

            IPAddress remoteEndpointAddress = IPAddress.Parse(ConfigurationManager.AppSettings["CERTCOPAddress"].ToString());
            int remoteEndpointPort = Int32.Parse(ConfigurationManager.AppSettings["CERTCOPPort"].ToString());

            IPEndPoint ipe = new IPEndPoint(remoteEndpointAddress, remoteEndpointPort);
            _tcpSocket = new Socket(ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
            _tcpSocket.Bind(localEndpoint);

            _tcpSocket.Connect(ipe);

            _tcpSocket.ReceiveTimeout = _socketTimeout;
        }

        public Object Receive()
        {
            List<byte> receivedBytesList = new List<byte>();

            try
            {
                do
                {
                    byte[] receivedBytes = new byte[_bufferSize];
                    int numBytes = _tcpSocket.Receive(receivedBytes);

                    if (numBytes == 0)
                        break;
                    else if (numBytes == _bufferSize)
                        receivedBytesList.AddRange(receivedBytes);
                    else
                    {
                        byte[] intByteArray = new byte[numBytes];
                        Array.Copy(receivedBytes, intByteArray, numBytes);
                        receivedBytesList.AddRange(intByteArray);
                    }

                } while (_tcpSocket.Available > 0);

                if (receivedBytesList.Count > 0)
                    return ObjectSerialization.DeserializeObjectFromXml(receivedBytesList.ToArray());
                else
                    return null;

            }
            catch (ObjectDisposedException)
            {
                return null;
            }
            catch (IOException)
            {
                return null;
            }
            catch (SocketException)
            {
                return null;
            }            
        }

        public void Send(Object obj)
        {
            byte[] objectBytes = ObjectSerialization.SerializeObjectAsXml(obj);

            try
            {
                _tcpSocket.Send(objectBytes);                
            }
            catch (IOException)
            {
                throw new ConnectionResetException();
            }
            catch (ObjectDisposedException)
            {
                throw new ConnectionResetException();
            }
        }
    }
}
